package com.study.springbootsecurity.filter.sms;

import com.study.springbootsecurity.entity.business.SmsCodeAuthenticationToken;
import com.study.springbootsecurity.entity.business.SmsCodeQuery;
import com.study.springbootsecurity.util.RequestBodyUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;

import java.io.IOException;

/**
 * @Description: TODO 手机认证过滤器
 * @author: Huangjianyun
 * @date: 2025-06-14 18:47
 */
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    public static final String SPRING_SECURITY_FORM_PHONE_KEY = "phone";
    public static final String SPRING_SECURITY_FORM_SMS_CODE_KEY = "code";
    private String phoneParameter = SPRING_SECURITY_FORM_PHONE_KEY;
    private String codeParameter = SPRING_SECURITY_FORM_SMS_CODE_KEY;
    private boolean postOnly = true;
    private final RequestBodyUtil requestBodyUtil = new RequestBodyUtil();

    /**
     * 构造函数，指定过滤器处理的URL
     * @param defaultFilterProcessesUrl 过滤器处理的URL
     */
    public SmsCodeAuthenticationFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }
    /**
     * 构造函数，指定需要进行认证的请求匹配器
     * @param requiresAuthenticationRequestMatcher 请求匹配器
     */
    public SmsCodeAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
        super(requiresAuthenticationRequestMatcher);
    }


    /**
     * 构造函数，
     *
     */
    public SmsCodeAuthenticationFilter() {
        super(PathPatternRequestMatcher.withDefaults()
                .matcher(HttpMethod.POST,"/api/user/smsLogin"));
    }

    /**
     * 尝试进行手机号验证码登录认证
     * @param request HTTP请求
     * @param response HTTP响应
     * @return 认证对象
     * @throws AuthenticationException 认证异常
     * @throws IOException IO异常
     * @throws ServletException Servlet异常
     */
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException {
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }  else {
            SmsCodeQuery smsCodeQuery = requestBodyUtil.getRequestBody(request, SmsCodeQuery.class);
            // 请求参数获取手机号
            String phone = smsCodeQuery.getPhone();
            phone = phone != null ? phone.trim() : "";
            // 请求参数获取验证码
            String smsCode = smsCodeQuery.getCode();
            smsCode = smsCode != null ? smsCode : "";
            // 认证基础数据封装未认证自定义验证码token 备用
            SmsCodeAuthenticationToken authRequest = SmsCodeAuthenticationToken.unauthenticated(phone, smsCode);
            this.setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }

    private String obtainCode(HttpServletRequest request) {
        return request.getParameter(this.codeParameter);
    }

    /**
     * 从请求中获取手机验证码参数
     * @param request HTTP请求
     * @return 手机号
     */
    @Nullable
    protected String obtainPhone(HttpServletRequest request) {
        return request.getParameter(this.phoneParameter);
    }


    protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
        authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

    public void setPhoneParameter(String phoneParameter) {
        Assert.hasText(phoneParameter, "phone parameter must not be empty or null");
        this.phoneParameter = phoneParameter;
    }

    public void setCodeParameter(String codeParameter) {
        Assert.hasText(codeParameter, "Password parameter must not be empty or null");
        this.codeParameter = codeParameter;
    }

    public final String getPhoneParameter() {
        return this.phoneParameter;
    }

    public final String getCodeParameter() {
        return this.codeParameter;
    }

//    static {
//        DEFAULT_ANT_PATH_REQUEST_MATCHER = PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, "/api/user/sms/login");
//    }
}
